package com.hohai.river.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hohai.river.annotation.Calculate;
import com.hohai.river.entity.MyIndex;
import com.hohai.river.entity.River;
import com.hohai.river.entity.Score;
import com.hohai.river.entity.SysIndex;
import com.hohai.river.service.RiverService;
import com.hohai.river.service.ScoreService;
import com.hohai.river.service.SysIndexService;
import com.hohai.river.utils.IndexCalculator;
import com.hohai.river.utils.JsonUtils;
import com.pig4cloud.pig.admin.api.feign.RemoteFileService;
import com.pig4cloud.pig.common.security.service.PigUser;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import feign.Response;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class IndexService {

	@Autowired
	private RiverService riverService;

	@Autowired
	private SysIndexService sysIndexService;

	@Resource
	RemoteFileService remoteFileService;

	@Autowired
	private ScoreService scoreService;

	@Autowired
	private IndexCalculator indexCalculator;

	/**
	 * 条件查询
	 * @param riverId 申请河湖ID
	 * @param fillType 填写类型
	 * @param service service
	 * @return T
	 */
	public <T> T conditionQuery(Long riverId, Integer fillType, IService<T> service) {
		QueryWrapper<T> wrapper = new QueryWrapper<>();
		wrapper.eq("fill_type", fillType).eq("river_id", riverId);
		if (fillType == 1) {
			PigUser user = SecurityUtils.getUser();
			wrapper.eq("update_by", user.getName());
		}
		return service.getOne(wrapper);
	}

	/**
	 * 删除文件
	 * @param id 指标填写记录ID
	 * @param fileName 文件名
	 * @param service service
	 * @return boolean
	 */
	public <T> boolean delFile(Long id, String fileName, IService<T> service) {
		MyIndex indexData = (MyIndex) service.getById(id);
		JSONArray jsonArray = JSON.parseArray(indexData.getFileList());
		List<Object> list = jsonArray.stream().filter(item -> {
			Map<String, String> map = (Map<String, String>) item;
			return !map.get("fileName").equals(fileName);
		}).collect(Collectors.toList());
		indexData.setFileList(JSON.toJSONString(list));
		Boolean data = (Boolean) remoteFileService.delFileByName(fileName).getData();
		if (data) {
			return service.updateById((T) indexData);
		}
		return false;
	}

	/**
	 * 保存指标
	 */
	@Transactional
	public <T> boolean addIndex(MyIndex myIndex, Long indexId, IService<T> service) {
		calculateScore(myIndex, indexId);
		service.save((T) myIndex);
		return saveScore(myIndex, indexId, service);
	}

	/**
	 * 更新指标
	 */
	@Transactional
	public <T> boolean updateIndex(MyIndex myIndex, Long indexId, IService<T> service) {
		calculateScore(myIndex, indexId);
		service.updateById((T) myIndex);
		return saveScore(myIndex, indexId, service);
	}

	/**
	 * 计算分数
	 * @param myIndex 指标
	 * @param indexId 指标表对应ID
	 */
	@SneakyThrows
	public void calculateScore(MyIndex myIndex, Long indexId) {
		River river = riverService.getById(myIndex.getRiverId());
		if (myIndex.getNoData() == 1) {
			SysIndex sysIndex = sysIndexService.getById(indexId);

			Response response = remoteFileService.file(JsonUtils.BUCKET, JsonUtils.FILE_NAME);

			double score = JsonUtils.getValueFromResponse(response, sysIndex.getIndexCode() + "Index",
					river.getLevel().toString(), myIndex.getSelfEvaluate());
			myIndex.setScore(score);
		}
		else {
			Class<?> clazz = myIndex.getClass();
			List<Class<?>> classList = new ArrayList<>();
			List<Object> valueList = new ArrayList<>();
			Field[] fields = clazz.getDeclaredFields();
			for (Field field : fields) {
				if (field.isAnnotationPresent(Calculate.class)) {
					classList.add(field.getType());
					field.setAccessible(true);
					valueList.add(field.get(myIndex));
				}
			}
			classList.add(Integer.class);
			valueList.add(river.getLevel());
			Class[] classes = classList.toArray(new Class[classList.size()]);
			double score = (double) indexCalculator.getClass()
					.getMethod(clazz.getSimpleName().toLowerCase() + "_calculator", classes)
					.invoke(indexCalculator, valueList.toArray());
			BigDecimal decimal = new BigDecimal(score);
			score = decimal.setScale(2, RoundingMode.DOWN).doubleValue();
			myIndex.setScore(score);
		}
	}

	/**
	 * 保存评分到score表
	 * @param index 指标
	 * @param indexId 指标表对应ID
	 * @param service service
	 * @return boolean
	 */
	private boolean saveScore(MyIndex index, Long indexId, IService service) {

		// 根据riverId, fillType=1，即查询专家评分列表
		QueryWrapper<MyIndex> wrapper = new QueryWrapper();
		wrapper.eq("fill_type", 1).eq("river_id", index.getRiverId());
		List<MyIndex> list = service.list(wrapper);

		Score scoreEntity = new Score().setRiverId(index.getRiverId()).setIndexId(indexId);

		if (index.getFillType() == 1) {
			double sum = list.stream().mapToDouble(MyIndex::getScore).sum();
			sum /= list.size();

			BigDecimal decimal = new BigDecimal(sum);
			sum = decimal.setScale(2, RoundingMode.DOWN).doubleValue();
			scoreEntity.setSystemScore(sum);
		}
		else {
			scoreEntity.setSelfScore(index.getScore());
		}

		Score queryScore = scoreService.getScore(index.getRiverId(), indexId);
		if (queryScore == null) {
			return scoreService.save(scoreEntity);
		}
		else if (index.getFillType().equals(1)) {
			String userId = SecurityUtils.getUser().getId().toString();
			JSONObject jsonObject;
			if (StringUtils.isEmpty(scoreEntity.getExpertList())) {
				jsonObject = new JSONObject();
				jsonObject.put(userId, index.getScore());
			}
			else {
				jsonObject = JSON.parseObject(scoreEntity.getExpertList());
				jsonObject.put(userId, index.getScore());
			}
			scoreEntity.setExpertList(jsonObject.toJSONString());
		}
		scoreEntity.setId(queryScore.getId());
		return scoreService.updateById(scoreEntity);
	}

}
